import cv2
import numpy as np

img = cv2.imread("../images/outline.png")

# 1. 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 2. 二值化
_, img_binary = cv2.threshold(
    img_gray,
    127,
    255,
    cv2.THRESH_BINARY + cv2.THRESH_OTSU
)

# 3. 高斯滤波
img_gaussian = cv2.GaussianBlur(
    img_binary,
    (5, 5),
    5
)

# 其实在这一块，还应该进行一次 形态学变换 开运算和闭运算 后面讲
# 它会把 牛牛VIP会员卡 二值化的结果给它填充白洞

# 4. 寻找轮廓
contours, _ = cv2.findContours(
    img_gaussian,
    mode=cv2.RETR_LIST,     # 查找轮廓的方式
    method=cv2.CHAIN_APPROX_SIMPLE  # 轮廓近似方法
)
# 寻找到的轮廓是一个列表，其中每个元素都是一个轮廓，轮廓是由点组成的 NumPy 数组
print(f"寻找到的轮廓的个数为：{len(contours)}")
for i, c in enumerate(contours):
    print(f"第{i+1}个轮廓的边界点的个位数为{len(c)}")

# 5. 绘制轮廓
# 一般不建议在原图上直接绘制
img_draw = img.copy()
cv2.drawContours(
    img_draw,
    contours=contours,  # 要绘制的轮廓列表
    contourIdx=-1,      # 要绘制轮廓的索引，-1表示都绘制，你也可以指定0 1 2 3 4 ...
    color=(0,0,255),
    thickness=2,        # -1表填充
    lineType=cv2.LINE_AA
)

# 6. 分析轮廓的凸包特征
hull = cv2.convexHull(
    points=contours[0]
)
print(len(hull))
print(hull)

# 7. 绘制凸包
cv2.polylines(
    img_draw,
    [hull],
    True,
    (255,0,0),
    2
)

# 8. 继续进行轮廓特征分析
# 8.1 外接矩形  [不考虑旋转，矩形的边与坐标轴是平行的]
x, y, w, h = cv2.boundingRect(hull)
cv2.rectangle(img_draw, (x,y), (x+w,y+h), (0,255,0), 2)

# 8.2 最小外接矩形
# 返回三元组ret —— 中心点坐标、宽度高度、旋转角度
ret = cv2.minAreaRect(hull)
# 因为绘制矩形需要的参数为 左上角和右下角坐标，而我们的返回值是（中心点坐标、宽度高度、旋转角度）
# 虽然通过数学计算能算出来，但是比较复杂，所以我们不采用绘制矩形的方式来绘制最小外接矩形，而是采用绘制轮廓的方式
# 补充一个函数    cv2.boxPoints() 可获取旋转矩形的四个顶点
box_points = np.int32(cv2.boxPoints(ret))
cv2.drawContours(img_draw, [box_points], -1, (255,255,0), 3)

# 8.3 最小外接圆
(x,y), radius = cv2.minEnclosingCircle(hull)
x, y, radius = np.int32((x, y, radius))     # 注意转换数据类型
cv2.circle(img_draw, (x,y), radius, (255,0,255), 3)

cv2.imshow("image", img_draw)
cv2.waitKey(0)